package org.flowers.unbeaten.logging.aop;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.flowers.unbeaten.base.constant.Constants;
import org.flowers.unbeaten.base.entity.Log;
import org.flowers.unbeaten.logging.aop.annotation.Logging;
import org.flowers.unbeaten.logging.aop.enums.LoggingType;
import org.flowers.unbeaten.logging.async.LoggingFactory;
import org.flowers.unbeaten.util.Id;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @description 日志切面实现
 * @author RyanWang
 * @date 2021-08-02 17:30:25
 * @version 1.0
 */
@Slf4j
@Aspect
@Component
public class LoggingAspect {

    @Autowired
    private LoggingFactory loggingFactory;

    /**
     * 切面编程
     * 只要出现@Logging注解都会进入
     */
    @Pointcut("@annotation(org.flowers.unbeaten.logging.aop.annotation.Logging) || @within(org.flowers.unbeaten.logging.aop.annotation.Logging)")
    public void loggingPointCut() {
    }

    /**
     * 环绕增强
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("loggingPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Log logging = new Log();
        Object result;
        try {
            // 获取日志切面
            Logging loggingAnnotation = getLogging(point);
            logging.setLogId(Id.generateId());
            logging.setTitle(loggingAnnotation.title());
            logging.setDescription(loggingAnnotation.describe());
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            // 请求的类名
            String className = point.getTarget().getClass().getName();
            // 请求的方法名
            String methodName = signature.getName();
            logging.setOperateUrl(className + "." + methodName + "()");
            // 请求的参数
            Object[] args = point.getArgs();
            String params = null;
            if (args.length != 0) {
                params = JSON.toJSONString(args);
            }
            logging.setRequestParam(params);
            logging.setBusinessType(loggingAnnotation.type());
            logging.setSuccess(true);
            // 设置日志的类型
            if (Constants.LOGIN_INTERFACE_NAME.equals(methodName)){
                logging.setLoggingType(LoggingType.LOGIN);
            }else {
                logging.setLoggingType(LoggingType.OPERATE);
            }
            result = point.proceed();
        } catch (Exception exception) {
            logging.setSuccess(false);
            logging.setErrorMessage(exception.getMessage());
            throw exception;
        } finally {
            loggingFactory.insertLog(logging);
        }
        return result;
    }

    /**
     * 获取日志注解
     * @param point 切点
     * @return
     */
    public Logging getLogging(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Class<? extends Object> targetClass = point.getTarget().getClass();
        Logging targetLogging = targetClass.getAnnotation(Logging.class);
        if (targetLogging != null) {
            return targetLogging;
        } else {
            Method method = signature.getMethod();
            Logging logging = method.getAnnotation(Logging.class);
            return logging;
        }
    }

}
